/*
 *  Copyright (C) 2025 ameise <ameise.wang@gmail.com> - All Rights Reserved
 *
 *  This file is part of e3utils.
 *
 *  e3utils is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  e3utils is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with e3utils. If not, see <https://www.gnu.org/licenses/>.
 */

package sys

import (
	"context"
	"fmt"
	"os"
	"os/signal"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"syscall"

	"gitee.com/ameise84/e3utils/internal"
)

var (
	_gOnce       sync.Once
	_gCancelFunc context.CancelFunc
	_gContext    context.Context
	_gExitLock   sync.Mutex
)

func GetGoroutineID() int {
	var buf [64]byte
	n := runtime.Stack(buf[:], false)
	idField := strings.Fields(strings.TrimPrefix(string(buf[:n]), "goroutine "))[0]
	id, err := strconv.Atoi(idField)
	if err != nil {
		panic(fmt.Sprintf("cannot get goroutine id: %v", err))
	}
	return id
}

// WaitKillSigint 等待关闭信号
func WaitKillSigint() {
	_gOnce.Do(func() {
		_gContext, _gCancelFunc = context.WithCancel(context.Background())
	})
	sigChan := make(chan os.Signal, 1)
	signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
	select {
	case _ = <-sigChan:
		internal.GetLogger().Trace("接收到kill信号,执行清理中...").Println()
	case <-_gContext.Done():
		internal.GetLogger().Trace("服务器上下文中断,执行清理中...").Println()
	}
}

func Exit(n int) {
	_gExitLock.Lock()
	defer _gExitLock.Unlock()
	internal.GetLogger().Trace(fmt.Sprintf("进程异常关闭,原因[%d]", n)).Println()
	if _gCancelFunc != nil {
		_gCancelFunc()
	} else {
		os.Exit(n)
	}
}
